<template>
	<view>
		<view :class="['modal', visible ? 'modal-show' : 'modal-hide']" @touchmove="true" @tap="cancel"></view>

		<view :class="['picker', visible ? 'picker-show' : 'picker-hide']">
			<view class="date-header" v-if="mode === 'date'">
				<view class="btn doubleLeft" @tap="changeDate" data-type="year-"><text class="iconfont icon-arrow-double-left"></text></view>
				<view class="btn left" @tap="changeDate" data-type="month-"><text class="iconfont icon-arrow-left"></text></view>

				<view class="month">{{ currentDateStr }}</view>

				<view class="btn right" @tap="changeDate" data-type="month+"><text class="iconfont icon-arrow-right"></text></view>
				<view class="btn doubleRight" @tap="changeDate" data-type="year+"><text class="iconfont icon-arrow-double-right"></text></view>
			</view>

			<view class="date-body" v-if="mode === 'date'">
				<view class="tr">
					<view class="th"><view class="cell">日</view></view>
					<view class="th"><view class="cell">一</view></view>
					<view class="th"><view class="cell">二</view></view>
					<view class="th"><view class="cell">三</view></view>
					<view class="th"><view class="cell">四</view></view>
					<view class="th"><view class="cell">五</view></view>
					<view class="th"><view class="cell">六</view></view>
				</view>

				<view class="tr" v-for="(tr, i) in currentData" :key="i">
					<view class="td" v-for="(td, j) in tr" :key="j" @tap="chooseDate(i, j)">
						<view hover-class="none" :class="['cell', td.currentMonth ? '' : 'otherMonth', td.valid ? '' : 'disabled', td.date && td.dateStr === selectedDateStr ? 'cur' : '']">
							{{ td.day }}
						</view>
					</view>
				</view>
			</view>

			<view class="time-header" v-if="mode === 'time'">
				<view class="date">{{ selectedDateShow }}</view>
			</view>

			<view class="time-body" v-if="mode === 'time'">
				<picker-view indicator-class="selectItem" :value="initTimeValue" @change="onTimeChange">
					<picker-view-column>
						<view v-for="(item, index) in hours" :key="index" class="item">{{ item }}时</view>
					</picker-view-column>
					<picker-view-column>
						<view v-for="(item, index) in minutes" :key="index" class="item">{{ item }}分</view>
					</picker-view-column>
					<picker-view-column>
						<view v-for="(item, index) in seconds" :key="index" class="item">{{ item }}秒</view>
					</picker-view-column>
				</picker-view>
			</view>

			<view class="bottom">
				<view class="btn btn-cancel" @tap="cancel" v-if="mode === 'date'"><view hover-class="hover" :hover-start-time="0">取消</view></view>
				<view class="btn btn-cancel" @tap="toggleMode" v-else><view hover-class="hover" :hover-start-time="0">返回</view></view>

				<view class="bd"></view>

				<view class="btn btn-confirm" @tap="toggleMode" v-if="mode === 'date'"><view hover-class="hover" :hover-start-time="0">选时间</view></view>
				<view class="btn btn-confirm" @tap="confirm" v-else><view hover-class="hover" :hover-start-time="0">完成</view></view>
			</view>
		</view>
	</view>
</template>

<script>
export default {
	props: {
		date: {
			// 当前日期, 时间戳格式
			type: Number
		},
		rangeStart: {
			// 最早可选日期, 时间戳格式
			type: Number
		},
		rangeEnd: {
			// 最晚可选日期, 时间戳格式
			type: Number
		},
		needWeek: {
			// 是否禁用周末, 默认不禁用
			type: Boolean,
			default: true
		},
		visible: {
			// 控制控件显示
			type: Boolean,
			default: false
		}
	},
	data() {
		let tmp1 = [],
			tmp2 = [],
			tmp3 = []
		for (let i = 0; i < 24; i++) {
			tmp1.push(i)
		}
		for (let i = 0; i < 60; i++) {
			tmp2.push(i)
			tmp3.push(i)
		}
		return {
			mode: 'date', // date:选择日期模式, time:选择时间模式
			startDate: null, // 最早可选日期
			endDate: null, // 最晚可选日期
			currentDate: null, // 当前月日期
			currentDateStr: null, // 2018-12
			selectedDate: null, // 选中日期
			selectedDateStr: null, // 选中日期字符格式,用于和dayStr比较
			selectedDateShow: null, // 选中日期显示 2018-12-12
			currentData: null, // 当前渲染数据
			hours: tmp1,
			minutes: tmp2,
			seconds: tmp3,
			initTimeValue: [0, 0, 0], // 初始化选中时间的时,分,秒
			timeValue: [0, 0, 0] // 选中时间的时,分,秒
		}
	},
	computed: {},
	watch: {
		date(newVal) {
			this.initDate(newVal)
		},
		rangeStart(newVal) {
			this.initRangeStart(newVal)
		},
		rangeEnd(newVal) {
			this.initRangeStart(newVal)
		}
	},
	mounted() {
		let { rangeStart, rangeEnd, date } = this
		this.initRangeStart(rangeStart)
		this.initRangeEnd(rangeEnd)
		this.initDate(date)
	},
	methods: {
		initRangeStart(value) {
			if (value) {
				let date = new Date(value)
				this.startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate())
			}
		},
		initRangeEnd(value) {
			if (value) {
				let date = new Date(value)
				this.endDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 24)
			}
		},
		initDate(value) {
			let date = value ? new Date(value) : new Date()
			let year = date.getFullYear(),
				month = date.getMonth(),
				day = date.getDate()

			this.setCurrentDate(new Date(year, month, day))
			this.setSelectedDate(new Date(year, month, day))
			this.setMonthData()
		},
		setCurrentDate(date) {
			if (!date) {
				this.currentDate = null
				this.currentDateStr = null
			} else {
				const year = date.getFullYear()
				const month = date.getMonth() + 1
				const dateStr = [year, month].map(this.fixZero).join('-')

				this.currentDate = date
				this.currentDateStr = dateStr
			}
		},
		setSelectedDate(date) {
			if (!date) {
				this.selectedDate = null
				this.selectedDateStr = null
				this.selectedDateShow = null
				return
			} else {
				const year = date.getFullYear()
				const month = date.getMonth() + 1
				const day = date.getDate()
				const selectedDateShow = [year, month, day].map(this.fixZero).join('-')

				this.selectedDate = date
				this.selectedDateStr = date.toString()
				this.selectedDateShow = selectedDateShow
			}
		},
		setMonthData() {
			const currentDate = this.currentDate

			let year = currentDate.getFullYear(),
				month = currentDate.getMonth()

			// 当月所有天数的数据结构
			let currentData = []

			// 获取当月1号的星期0~6
			let firstDayWeek = new Date(year, month, 1).getDay()

			// 天数, 用来标识当前是本月中的哪一天
			let dayIndex = 0

			// 第1行
			let firstCol = []

			for (let i = 0; i < 7; i++) {
				if (i < firstDayWeek) {
					let date = new Date(year, month, dayIndex - (firstDayWeek - i) + 1) //0-5+0+1=-4,-3,-2,-1,0
					let valid = this.isValidDay(date)
					firstCol.push({
						date: date,
						dateStr: date.toString(),
						day: date.getDate(),
						valid: valid,
						currentMonth: false
					})
				} else {
					dayIndex += 1
					let date = new Date(year, month, dayIndex)
					let valid = this.isValidDay(date)
					firstCol.push({
						date: date,
						dateStr: date.toString(),
						day: dayIndex,
						valid: valid,
						currentMonth: true
					})
				}
			}

			currentData.push(firstCol)

			// 第2～4行
			for (let i = 0; i < 3; i++) {
				let col = []
				for (let j = 0; j < 7; j++) {
					dayIndex += 1
					let date = new Date(year, month, dayIndex)
					let valid = this.isValidDay(date)
					col.push({
						date: date,
						dateStr: date.toString(),
						day: dayIndex,
						valid: valid,
						currentMonth: true
					})
				}
				currentData.push(col)
			}

			// 第5行
			let lastCol = []

			console.log('let restDay = new Date(year, month + 1, 0).getDate() - dayIndex', dayIndex)

			// 余下一行中本月的天数
			//3*7=21+x=30/31
			let restDay = new Date(year, month + 1, 0).getDate() - dayIndex //31-23=8, 31-28=3

			for (let i = 0; i < 7; i++) {
				if (i < restDay) {
					dayIndex += 1
					let date = new Date(year, month, dayIndex)
					let valid = this.isValidDay(date)
					lastCol.push({
						date: date,
						dateStr: date.toString(),
						day: dayIndex,
						valid: valid,
						currentMonth: true
					})
				} else {
					let date = new Date(year, month + 1, i - restDay + 1) //3-3+1=1,2,3,4,
					let valid = this.isValidDay(date)
					lastCol.push({
						date: date,
						dateStr: date.toString(),
						day: date.getDate(),
						valid: valid,
						currentMonth: false
					})
				}
			}

			currentData.push(lastCol)

			let restDay2 = restDay - 7 //8-7=1, 7-7=0,3-7=-4

			// 第6行
			let lastCol2 = []

			for (let i = 0; i < 7; i++) {
				if (i < restDay2) {
					dayIndex += 1
					let date = new Date(year, month, dayIndex)
					let valid = this.isValidDay(date)
					lastCol2.push({
						date: date,
						dateStr: date.toString(),
						day: dayIndex,
						valid: valid,
						currentMonth: true
					})
				} else {
					let date = new Date(year, month + 1, i - restDay2 + 1)
					let valid = this.isValidDay(date)
					lastCol2.push({
						date: date,
						dateStr: date.toString(),
						day: date.getDate(),
						valid: valid,
						currentMonth: false
					})
				}
			}

			currentData.push(lastCol2)
			this.currentData = currentData
		},
		isValidDay(date) {
			let { startDate, endDate, needWeek } = this

			let valid = false

			if (startDate && endDate) {
				// 开始日期和结束日期都存在
				if (date >= startDate && date < endDate) {
					valid = true
				}
			} else if (startDate && !endDate) {
				// 开始日期存在结束日期不存在
				if (date >= startDate) {
					valid = true
				}
			} else if (!startDate && endDate) {
				// 开始日期不存在结束日期存在
				if (date < endDate) {
					valid = true
				}
			} else {
				valid = true
			}

			if (!needWeek) {
				let weekDay = date.getDay()
				if (weekDay === 0 || weekDay === 6) {
					valid = false
				}
			}

			return valid
		},
		onTimeChange(e) {
			const values = e.detail.value
			this.timeValue = values
		},
		toggleMode() {
			//切换模式
			if (this.mode === 'date') {
				let date = this.date ? new Date(this.date) : new Date()
				let hour = date.getHours()
				let minute = date.getMinutes()
				let second = date.getSeconds()

				this.initTimeValue = [hour, minute, second]
				this.timeValue = [hour, minute, second]
				this.mode = 'time'
			} else {
				this.mode = 'date'
			}
		},
		cancel() {
			this.$emit('update:visible', false)

			setTimeout(() => {
				this.mode = 'date'
			}, 300)

			this.initDate(this.date)
		},
		confirm() {
			this.$emit('update:visible', false)
			this.mode = 'date'

			let selectedDate = this.selectedDate
			let year = selectedDate.getFullYear(),
				month = selectedDate.getMonth(),
				day = selectedDate.getDate()

			let timeValue = this.timeValue
			let newDate = new Date(year, month, day, timeValue[0], timeValue[1], timeValue[2])
			let dateStr = [year, month, day].map(this.fixZero).join('-')
			let dateTimeStr = [year, month, day].map(this.fixZero).join('-') + ' ' + timeValue.map(this.fixZero).join(':')

			this.$emit('confirm', { date: newDate, dateStr: dateStr, dateTimeStr: dateTimeStr })
		},
		changeDate(event) {
			let currentDate = this.currentDate
			let year = currentDate.getFullYear(),
				month = currentDate.getMonth()
			let type = event.currentTarget.dataset.type

			switch (type) {
				case 'year-':
					currentDate.setFullYear(year - 1)
					break
				case 'year+':
					currentDate.setFullYear(year + 1)
					break
				case 'month-':
					currentDate.setMonth(month - 1)
					break
				case 'month+':
					currentDate.setMonth(month + 1)
					break
			}

			this.setCurrentDate(currentDate)
			this.setMonthData()
		},
		chooseDate(i, j) {
			// let { i, j } = event.currentTarget.dataset

			let td = this.currentData[i][j]

			if (td.valid) {
				this.setSelectedDate(td.date)
			}
		},
		fixZero(value) {
			if (value < 10) {
				return '0' + value
			} else {
				return value
			}
		}
	}
}
</script>

<style lang="scss">
@import '~@/common/css/variables';

@font-face {
	font-family: 'iconfont';
	src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAANgAAsAAAAACCQAAAMSAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDIgqDMIJTATYCJAMUCwwABCAFhG0HaxvyBsgekiQBOQsUTYOIACAoHv5/v2/7XHmj0maSavfVBTHJxF/BGyWziJoJkWiS4d799NoBUQaSCGzxkv4V0pefkSLSZT1C26mpsZAkzIRuf8AoZfufy+ldQ3z+9/Lc1t48NkdRoAW0N7bJLpACDUQbxm4iaIinCXQaV06zNzg+D9EKMCkQdxVmgOiMSmnIDu1CU7GyiBdQtaeH2k885++Pv9ainaRmYOb+9QEzdP+AH8thrdCmsxQB9nQGGOvIWAAKcbnSdFZYFFoQptObEW4FaBQh/YDB5VCIKZlcxTYdnbD+ebJENEBmN9iSw4UfMCsRhyzExUlWyLJ4WQ5LeJ6VdKLBfeApIJlQjSGpv3VwMC01PYVtZTHv6eVmuhnd/ouTTOph19yn14FMyrxbV8fpZtdmRnwrrqhQW1RxdtWTjnoC1+cZCerLrCzvlo3p8cVmBppdvsvzLDXXu2kjJdiz8v53gmBZOrzXdeLi3/u2T/D/qtXBx7q4N3n5hYWB3Lo8X2OTP88/GZq1tatnr+06P7+oqhl4GSPQfhXAkA80Nvny6nIDhYV5+U9xda+CW3Ul/qLC/PxrEX6+ggfAiPQxDfkaz89yTvsrqX5+retr/9ceV8Cnw5IUVdFd0n4D5uD3sDvWFJ8L1LW4+ZjlWqrJCQIJnVDNj8mFQT/TSEY6ZxLajSSQtBmDrN0EWogLUHXZgEa7Teg0b2h9lyFCmCgdmLMnQeh3D0mvD5D1+0IL8RuqUf/Q6I8MnY5H2o5dpuJWbJ9Ag0QzMa4TxcQdFGllrMieRbZsM4g0l5MWUaiKl9RUVuejQ+hAMcUcdYXVSkkJFdxOBqXz0GbjxCn4EppkpUVKZ2tVFa16UaWJ2yHWLgEZSMiMMFpHKEw4B0pbS7EF7GchZpmNgWgo6DEuQoJK6Z6oUam6AzokcnQquJVLVCuYWpJEEZTA2RGD0jBkY8MRzuphS5CJVMkyIODUqgo2ol1FlctL7C+QaZQATq6RIkeJGo3OS0Lw1QobUpkSp5j5stGGBUJcR6Ewi0xtYLlKAAAA')
		format('woff2');
}

.iconfont {
	font-family: 'iconfont' !important;
	font-size: 28rpx;
	font-style: normal;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.icon-arrow-left:before {
	content: '\e601';
}

.icon-arrow-double-left:before {
	content: '\e62f';
}

.icon-arrow-right:before {
	content: '\e602';
}

.icon-arrow-double-right:before {
	content: '\e600';
}

.picker {
	width: 600rpx;
	position: fixed;
	left: 50%;
	top: 45%;
	z-index: 999999;
	text-align: center;
	box-sizing: border-box;
	opacity: 0;
	transform: scale(0) translate3D(-50%, -50%, 0);
	border-radius: 20rpx;
	overflow: hidden;
	background: #fff;

	&.picker-show {
		transition: transform 0s, opacity 0.3s;
		transform: scale(1) translate3D(-50%, -50%, 0);
		opacity: 1;
	}

	&.picker-hide {
		transition: transform 0s 0.3s, opacity 0.3s;
	}

	$head-height: 80rpx;

	.date-header {
		border-bottom: 1rpx solid $lineColor;
		height: $head-height;
		line-height: $head-height;
		text-align: center;
		padding: 0 0.5rem;
		position: relative;
		box-sizing: border-box;

		.btn {
			box-sizing: border-box;
			padding: 0 20rpx;
			height: $head-height;
			cursor: pointer;
			position: absolute;
			top: 0;
			font-size: 0;
			-webkit-tap-highlight-color: rgba(0, 0, 0, 0);

			.iconfont {
				line-height: 80rpx;
				font-size: 40rpx;
				color: $mainColor;
			}
		}

		.doubleLeft {
			left: 0;
		}

		.left {
			left: 80rpx;
		}

		.doubleRight {
			right: 0;
		}

		.right {
			right: 80rpx;
		}

		.month {
			font-size: 36rpx;
			font-weight: bold;
		}
	}

	.date-body {
		font-size: 30rpx;

		.tr {
			display: flex;
			align-items: center;

			& > .th {
				flex: 1;

				& > .cell {
					display: inline-block;
					width: 60rpx;
					height: 60rpx;
					line-height: 60rpx;
					margin: 6rpx;
					font-weight: bold;
				}
			}

			& > .td {
				flex: 1;

				& > .cell {
					display: inline-block;
					width: 60rpx;
					height: 60rpx;
					line-height: 60rpx;
					margin: 6rpx;
					cursor: pointer;
					border-radius: 50%;
					-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
					color: $mainBlack1;

					&.otherMonth {
						color: $mainBlack3;
					}

					&.cur {
						background-color: $mainColor !important;
						color: #ffffff;
					}

					&.disabled {
						color: #cccccc;
						background: #efefef;
						cursor: not-allowed;
					}
				}
			}
		}
	}

	.time-header {
		border-bottom: 1rpx solid $lineColor;
		height: $head-height;
		line-height: $head-height;
		text-align: center;
		position: relative;
		font-weight: bold;

		.date {
			font-size: 36rpx;
		}
	}

	.time-body {
		font-size: 30rpx;

		picker-view {
			width: 100%;
			height: 504rpx;

			.item {
				line-height: 72rpx;
			}

			.selectItem {
				height: 72rpx;
			}
		}
	}

	.bottom {
		display: flex;
		align-items: center;
		padding: 12rpx;
		border-top: 1rpx solid $lineColor;
		box-sizing: border-box;

		.bd {
			flex: 1;
		}

		.btn {
			padding: 20rpx;
			margin: -20rpx;

			& > view {
				min-width: 100rpx;
				font-size: 30rpx;
				padding: 8rpx 10rpx;
				text-align: center;
				border-radius: 8rpx;
				color: #ffffff;
			}
		}

		.btn-cancel {
			& > view {
				background: $mainBlack3;
				transition: background-color 0.3s;

				&.hover {
					background: rgba($mainBlack3, 0.7);
				}
			}
		}

		.btn-confirm {
			& > view {
				background: $mainColor;
				transition: background-color 0.3s;

				&.hover {
					background: $mainColorActive;
				}
			}
		}
	}
}

.modal {
	position: fixed;
	left: 0;
	right: 0;
	top: 0;
	bottom: 0;
	z-index: 2;
	background: rgba(0, 0, 0, 0.6);
	opacity: 0;
	transform: translateY(100%);

	&.modal-show {
		transition: transform 0s, opacity 0.3s;
		transform: translateY(0%);
		opacity: 1;
	}

	&.modal-hide {
		transition: transform 0s 0.3s, opacity 0.3s;
	}
}
</style>
